package org.durcframework.core;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class UserFilter implements Filter {

	private static PathMapper<Boolean> pathMapper = null;
	private String loginUrl = "login.jsp";

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) arg0;
		HttpServletResponse response = (HttpServletResponse) arg1;
		WebContext.getInstance().setRequest(request);

		if (isLogin(request)) {
			arg2.doFilter(arg0, arg1);
		} else {
			redirect(request, response);
		}
	}

	/**
	 * 跳转
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	protected void redirect(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		// 如果是ajax请求
		/*
		 * 前台页面可以这样处理 if (typeof(jQuery) != 'undefined') {
		 * $(document).ajaxError(function (event, request, settings) { if
		 * (request.getResponseHeader("X-timeout") && request.status == 401) {
		 * // 跳转到首页 top.location.href = ctx; }else{ alert("系统异常"); } }); }
		 * 这段代码放在页面底部即可
		 */
		if (isAjaxRequest(request)) {
			response.setHeader("X-timeout", "1");
			response.setStatus(401);
			response.getWriter().close();
			return;
		}
		response.sendRedirect(request.getContextPath() + "/"
				+ getNeedLoginPage());
	}

	/**
	 * 判断请求是否为Ajax请求. <br/>
	 * 
	 * @param request
	 *            请求对象
	 * @return boolean
	 */
	public boolean isAjaxRequest(HttpServletRequest request) {
		String header = request.getHeader("X-Requested-With");
		return "XMLHttpRequest".equals(header);
	}

	/**
	 * 用户登陆页面
	 * 
	 * @return
	 */
	protected String getNeedLoginPage() {
		return loginUrl;
	}

	/**
	 * 用户是否登录,如果没有登录则被拦截,跳转到getNeedLoginPage()页面
	 * 
	 * @param request
	 * @return true,已登录
	 */
	protected boolean isLogin(HttpServletRequest request) {

		boolean isExcludeUrl = isExcludeUrl(request);

		if (isExcludeUrl) {
			return true;
		}

		return UserContext.getInstance().getUser() != null;
	}

	/**
	 * 该路径是否不需要登录检测
	 * @param request
	 * @return 返回true,不需要登录检测
	 */
	protected boolean isExcludeUrl(HttpServletRequest request) {
		String uri = getRequestPath(request);
		return getPathMapper().get(uri) != null;
	}

	/**
	 * 获取请求路径,即contextPath后面部分.
	 * 如http://www.aaa.com/rms/sys/index.jsp<br>
	 * 返回/sys/index.jsp
	 * @param request
	 * @return
	 */
	public static String getRequestPath(HttpServletRequest request) {
		String result = request.getServletPath();
		String pathInfo = request.getPathInfo();

		if (pathInfo != null) {
			result = result + pathInfo;
		}

		// getServletPath() returns null unless the mapping corresponds to a
		// servlet
		if (result == null) {
			String requestURI = request.getRequestURI();
			if (request.getPathInfo() != null) {
				// strip the pathInfo from the requestURI
				return requestURI.substring(0,
						requestURI.indexOf(request.getPathInfo()));
			} else {
				return requestURI;
			}
		} else if ("".equals(result)) {
			// in servlet 2.4, if a request is mapped to '/*', getServletPath
			// returns null (SIM-130)
			return request.getPathInfo();
		} else {
			return result;
		}
	}

	public static PathMapper<Boolean> getPathMapper() {
		return pathMapper;
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		String paramValue = filterConfig.getInitParameter("excludeUrl");
		String loginUrl = filterConfig.getInitParameter("loginUrl");
		
		if(paramValue != null) {
			String[] patterns = paramValue.split(",");
			
			pathMapper = new PathMapper<Boolean>();
			
			for (String urlPattern : patterns) {
				if (urlPattern != null) {
					pathMapper.put(urlPattern.trim(), Boolean.TRUE);
				}
			}
		}
		
		if(loginUrl != null) {
			this.loginUrl = loginUrl;
		}
		
	}
}
